#include "Spark/Net/EventLoop.h"
#include <vector>
#include <unordered_set>
#include <deque>

using EntryPtr = std::shared_ptr<void>;
using BucketEntry = std::unordered_set<EntryPtr>;
using BucketQueue = std::deque<BucketEntry>;

constexpr size_t TIMING_TICK_INTERVAL{100};
constexpr size_t TIMING_BUKECT_PER_WHEEL = 100;

class TimingWheel
{
  public:
    class Defer
    {
      private:
        std::function<void()> cb_;

      public:
        Defer(std::function<void()> cb) : cb_(std::move(cb))
        {
        }
        ~Defer()
        {
            cb_();
        }
    };

  public:
    /**
     * @brief Construct a new Timing Wheel object
     * @param  loop Owner loop
     * @param  maxTimeout timeout in milliseconds
     * @param  ticksInterval inverval milliseconds
     * @param  bucketsPerWheel
     */
    TimingWheel(EventLoop* loop,
                size_t maxTimeout,
                size_t ticksInterval = TIMING_TICK_INTERVAL,
                size_t bucketsPerWheel = TIMING_BUKECT_PER_WHEEL);
    ~TimingWheel();

    void insertEntry(int delay, EntryPtr ep);
    EventLoop* getLoop() const
    {
        return loop_;
    }

  private:
    void insertEntryInLoop(int delay, EntryPtr ep);

  private:
    EventLoop* loop_;
    std::vector<BucketQueue> wheels_;
    std::atomic<size_t> ticks_{0};
    TimerID timerId_;
    size_t tickInterval_;
    size_t wheelsNum_;
    size_t bucketsPerWheel_;
};